package developer.算法.动态规划.乘积最大子数组;

/**
 * @author zhangyongkang
 * @time 2025/4/8 20:43
 * @description 给你一个整数数组 nums ，
 * 请你找出数组中乘积最大的非空连续 子数组（该子数组中至少包含一个数字），并返回该子数组所对应的乘积。
 * <p>
 * 测试用例的答案是一个 32-位 整数。
 * <p>
 * <p>
 * <p>
 * 示例 1:
 * <p>
 * 输入: nums = [2,3,-2,4]
 * 输出: 6
 * 解释: 子数组 [2,3] 有最大乘积 6。
 * 示例 2:
 * <p>
 * 输入: nums = [-2,0,-1]
 * 输出: 0
 * 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
 * <p>
 * <p>
 * 提示:
 * <p>
 * 1 <= nums.length <= 2 * 104
 * -10 <= nums[i] <= 10
 * nums 的任何子数组的乘积都 保证 是一个 32-位 整数
 */
public class MaxChengjiSonArray {

    public static void main(String[] args) {
        Solution3 solution = new Solution3();
        System.out.println(solution.maxProduct(new int[]{-2, 0, -1}));
        System.out.println(solution.maxProduct(new int[]{2, 3, -2, 4}));
    }

    static class Solution3 {
        public int maxProduct(int[] nums) {
            int[] dfsMin = new int[nums.length];
            int[] dfsMax = new int[nums.length];

            dfsMin[0] = nums[0];
            dfsMax[0] = nums[0];
            int max = Integer.MIN_VALUE;
            for (int i = 1; i < nums.length; i++) {
                //关键点： 需要是连续的 所以只需要考虑 当前节点/当前节点是否加入上个节点
                int num = nums[i];
                dfsMin[i] = Math.min(num, Math.min(dfsMin[i - 1] * num, dfsMax[i - 1] * num));
                dfsMax[i] = Math.max(num, Math.max(dfsMax[i - 1] * num, dfsMin[i - 1] * num));
                max = Math.max(dfsMax[i], max);
            }
            return max;

        }
    }

    static class Solution {
        public int maxProduct(int[] nums) {

            //根据正负情况进行考虑
            int[] numMax = new int[nums.length];
            int[] numMin = new int[nums.length];

            for (int i = 0; i < nums.length; i++) {
                numMax[i] = nums[i];
                numMin[i] = nums[i];
            }

            for (int i = 1; i <= nums.length - 1; i++) {
                int num = nums[i];
                //因为会出现负负得正的场景
                numMax[i] = Math.max(numMax[i - 1] * num, Math.max(num, numMin[i - 1] * num));
                numMin[i] = Math.min(numMin[i - 1] * num, Math.min(num, numMax[i - 1] * num));
            }

            int max = nums[0];
            for (int i = 0; i < numMax.length; i++) {
                max = Math.max(numMax[i], max);
            }
            return max;
        }
    }


    /**
     * 作者：力扣官方题解
     * 链接：https://leetcode.cn/problems/maximum-product-subarray/solutions/250015/cheng-ji-zui-da-zi-shu-zu-by-leetcode-solution/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     */
    static class SolutionOfficial {
        public int maxProduct(int[] nums) {
            int length = nums.length;
            long[] maxF = new long[length];
            long[] minF = new long[length];
            for (int i = 0; i < length; i++) {
                maxF[i] = nums[i];
                minF[i] = nums[i];
            }
            for (int i = 1; i < length; ++i) {
                maxF[i] = Math.max(maxF[i - 1] * nums[i], Math.max(nums[i], minF[i - 1] * nums[i]));
                minF[i] = Math.min(minF[i - 1] * nums[i], Math.min(nums[i], maxF[i - 1] * nums[i]));
                if (minF[i] < (-1 << 31)) {
                    minF[i] = nums[i];
                }
            }
            int ans = (int) maxF[0];
            for (int i = 1; i < length; ++i) {
                ans = Math.max(ans, (int) maxF[i]);
            }
            return ans;
        }
    }

    /**
     * 作者：力扣官方题解
     * 链接：https://leetcode.cn/problems/maximum-product-subarray/solutions/250015/cheng-ji-zui-da-zi-shu-zu-by-leetcode-solution/
     * 来源：力扣（LeetCode）
     * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
     */
    class SolutionOffical2 {
        public int maxProduct(int[] nums) {
            long maxF = nums[0], minF = nums[0];
            int ans = nums[0];
            int length = nums.length;
            for (int i = 1; i < length; ++i) {
                long mx = maxF, mn = minF;
                maxF = Math.max(mx * nums[i], Math.max(nums[i], mn * nums[i]));
                minF = Math.min(mn * nums[i], Math.min(nums[i], mx * nums[i]));
                if (minF < -1 << 31) {
                    minF = nums[i];
                }
                ans = Math.max((int) maxF, ans);
            }
            return ans;
        }
    }


}
